# coding: utf-8


class StateMachine(object):
    """ A state machine targeting the singleton update process.

    A normal workflow will look like:
    >>> sm = StateMachine('init')
    >>> @sm.state('init')
    >>> def init():
    >>>   print('init.')
    >>>   return 'next'
    >>> @sm.state('next')
    >>> def next():
    >>>   print('processed sth.')
    >>>   return 'done'
    >>> @sm.state('done')
    >>> def done():
    >>>   print('done.')
    >>>   return 'done'
    >>> sm.update()
    init.
    >>> sm.update()
    processed sth.
    >>> sm.update()
    done.

    """

    def __init__(self, init_state: str):
        """ Setup a state machine with initial state.
        :param init_state: the initial state name.
        :return: the state machine.
        """
        super(StateMachine, self).__init__()
        self._state = init_state
        self._states = dict()

    def state(self, name):
        """ Add state to the machine.
        :param name: the name of the machine.
        :return: the wrap function.
        """
        def wrap(func):
            self._states[name] = func

        return wrap

    def update(self, *args, **kwargs):
        """ The update process.
        On each call to this method, the state will be changed according to the method of current state.
        :param args: the args
        :param kwargs: the key word args.
        """
        current_state = self._states.get(self._state, None)
        if callable(current_state):
            self._state = current_state(*args, **kwargs)